package com.lekang.service.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.lekang.common.core.domain.AjaxResult;
import com.lekang.common.utils.DateUtils;
import com.lekang.common.utils.SecurityUtils;
import com.lekang.common.utils.StringUtils;
import com.lekang.domain.NursingItemPlanBinding;
import com.lekang.domain.NursingItemPlanBindingDTO;
import com.lekang.domain.NursingLevel;
import com.lekang.mapper.NursingItemPlanBindingMapper;
import com.lekang.mapper.NursingLevelMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.lekang.mapper.NursingPlanMapper;
import com.lekang.domain.NursingPlan;
import com.lekang.service.INursingPlanService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 护理计划Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-10-14
 */
@Service
public class NursingPlanServiceImpl implements INursingPlanService 
{
    @Autowired
    private NursingPlanMapper nursingPlanMapper;

    @Autowired
    private NursingItemPlanBindingMapper bindingMapper;
    
    @Autowired
    private NursingLevelMapper nursingLevelMapper;

    /**
     * 查询护理计划
     * 
     * @param id 护理计划主键
     * @return 护理计划
     */
    @Override
    public NursingPlan selectNursingPlanById(Long id)
    {
        return nursingPlanMapper.selectNursingPlanById(id);
    }

    /**
     * 查询护理计划列表
     * 
     * @param nursingPlan 护理计划
     * @return 护理计划
     */
    @Override
    public List<NursingPlan> selectNursingPlanList(NursingPlan nursingPlan)
    {
        List<NursingPlan> list = nursingPlanMapper.selectNursingPlanList(nursingPlan);
        // 为每个护理计划设置是否被护理等级使用的标识
        for (NursingPlan plan : list) {
            int levelCount = nursingPlanMapper.countLevelsByPlanId(plan.getId());
            plan.setIsUsedByLevel(levelCount > 0);
        }
        return list;
    }

    /**
     * 新增护理计划
     * 
     * @param nursingPlan 护理计划
     * @return 结果
     */
    @Override
    public int insertNursingPlan(NursingPlan nursingPlan)
    {
        nursingPlan.setCreateTime(DateUtils.getNowDate());
        return nursingPlanMapper.insertNursingPlan(nursingPlan);
    }

    /**
     * 修改护理计划
     * 
     * @param nursingPlan 护理计划
     * @return 结果
     */
    @Override
    public int updateNursingPlan(NursingPlan nursingPlan)
    {
        // 校验：是否被护理等级使用（禁用时也需要校验）
        int levelCount = nursingPlanMapper.countLevelsByPlanId(nursingPlan.getId());
        if (levelCount > 0) {
            throw new RuntimeException("该护理计划已被 " + levelCount + " 个护理等级使用，无法修改");
        }
        return nursingPlanMapper.updateNursingPlan(nursingPlan);
    }

    /**
     * 批量删除护理计划
     * 
     * @param ids 需要删除的护理计划主键
     * @return 结果
     */
    @Override
    public int deleteNursingPlanByIds(Long[] ids)
    {
        // 检查每个护理计划是否被使用
        for (Long id : ids) {
            int levelCount = nursingPlanMapper.countLevelsByPlanId(id);
            if (levelCount > 0) {
                NursingPlan plan = nursingPlanMapper.selectNursingPlanById(id);
                String planName = (plan != null) ? plan.getPlanName() : "ID=" + id;
                throw new RuntimeException("护理计划【" + planName + "】已被 " + levelCount + " 个护理等级使用，无法删除");
            }
        }
        return nursingPlanMapper.deleteNursingPlanByIds(ids);
    }

    /**
     * 删除护理计划信息
     * 
     * @param id 护理计划主键
     * @return 结果
     */
    @Override
    public int deleteNursingPlanById(Long id)
    {
        // 校验：是否被护理等级使用
        int levelCount = nursingPlanMapper.countLevelsByPlanId(id);
        if (levelCount > 0) {
            NursingPlan plan = nursingPlanMapper.selectNursingPlanById(id);
            String planName = (plan != null) ? plan.getPlanName() : "ID=" + id;
            throw new RuntimeException("护理计划【" + planName + "】已被 " + levelCount + " 个护理等级使用，无法删除");
        }
        return nursingPlanMapper.deleteNursingPlanById(id);
    }

    @Override
    public List<NursingPlan> selectEnableNursingPlan() {
       NursingPlan query = new NursingPlan();
       query.setStatus(1L);
       return  nursingPlanMapper.selectNursingPlanList(query);

    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 事务保证主表+中间表要么都成功，要么都回滚
    public AjaxResult addNursingPlanWithItems(NursingPlan plan) {

        // 1. 校验：护理计划名称唯一
        if (StringUtils.isNotEmpty(plan.getPlanName())) {
            NursingPlan existPlan = nursingPlanMapper.selectNursingPlanByName(plan.getPlanName());
            if (existPlan != null) {
                return AjaxResult.error("护理计划名称已存在");
            }
        }

        // 2. 设置创建时间和创建人（修复：避免数据库字段无默认值错误）
        plan.setCreateTime(new Date());
        plan.setCreator(SecurityUtils.getUserId());

        // 3. 插入护理计划主表，获取自增ID
        int mainResult = nursingPlanMapper.insertNursingPlan(plan);
        if (mainResult <= 0) {
            return AjaxResult.error("新增护理计划失败");
        }
        Long planId = plan.getId(); // 主表插入后，ID由自增生成

        // 3. 批量插入中间表（关联护理项目）
        List<NursingItemPlanBindingDTO> items = plan.getNursingItems();
        if (CollectionUtils.isEmpty(items)) {
            return AjaxResult.error("护理项目不能为空，请至少选择一项");
        }
        // 转换DTO为中间表实体，并设置“护理计划ID”
        List<NursingItemPlanBinding> bindingList = items.stream().map(dto -> {
            NursingItemPlanBinding binding = new NursingItemPlanBinding();
            binding
                    .setNursingItemId(dto.getNursingItemId());
            binding
                    .setNursingPlanId(planId);
            binding
                    .setServiceTime(dto.getServiceTime());
            binding
                    .setExecutionCycle(dto.getExecutionCycle());
            binding
                    .setExecutionFrequency(dto.getExecutionFrequency());
            return binding;
        }).collect(Collectors.toList());
        int bindingResult = bindingMapper.insertBatch(bindingList, planId);
        if (bindingResult != items.size()) {
            return AjaxResult.error("关联护理项目失败，请重试");
        }

        // 4. 计算并更新关联护理等级的费用
        updateRelatedNursingLevelFee(planId);

        return AjaxResult.success("新增成功");

    }

    @Override
    @Transactional
    public AjaxResult updateNursingPlanWithItems(NursingPlan plan) {

        // 0. 校验：是否被护理等级使用
        int levelCount = nursingPlanMapper.countLevelsByPlanId(plan.getId());
        if (levelCount > 0) {
            return AjaxResult.error("该护理计划已被 " + levelCount + " 个护理等级使用，无法修改");
        }

        // 1. 校验护理计划名称是否重复（排除自身）
        if (StringUtils.isNotEmpty(plan.getPlanName())) {
            NursingPlan existPlan = nursingPlanMapper.selectNursingPlanByName(plan.getPlanName());
            if (existPlan != null && !existPlan.getId().equals(plan.getId())) {
                return AjaxResult.error("护理计划名称已存在");
            }
        }

        // 2. 更新护理计划主表（原有逻辑保留）
        int rows = nursingPlanMapper.updateNursingPlan(plan);
        if (rows <= 0) {
            return AjaxResult.error("修改护理计划失败");
        }

        // 2. 删除旧关联记录：改用 NursingItemPlanBindingMapper
        bindingMapper.deleteByPlanId(plan.getId()); // 替换原来的 nursingPlanMapper.deleteNursingItemBindingsByPlanId(...)

        // 3. 批量插入新关联（原有逻辑保留，参数已匹配）
        if (plan.getNursingItems() != null && !plan.getNursingItems().isEmpty()) {
            nursingPlanMapper.batchInsertNursingItemBindings(plan.getId(), plan.getNursingItems());
        }

        // 4. 重新计算并更新关联护理等级的费用
        updateRelatedNursingLevelFee(plan.getId());

        return AjaxResult.success("修改成功");
    }
    
    /**
     * 计算护理计划的月费用总和
     * 
     * @param planId 护理计划ID
     * @return 月费用总和
     */
    @Override
    public BigDecimal calculatePlanMonthlyFee(Long planId) {
        // 查询护理计划绑定的所有项目（包含价格、执行周期、执行频次）
        List<Map<String, Object>> items = bindingMapper.selectPlanItemsWithPrice(planId);
        
        System.out.println("【费用计算】护理计划ID=" + planId + "，绑定的护理项目数量=" + (items != null ? items.size() : 0));
        
        if (items == null || items.isEmpty()) {
            System.out.println("【费用计算】该护理计划未绑定任何护理项目，费用为0");
            return BigDecimal.ZERO;
        }
        
        BigDecimal totalFee = BigDecimal.ZERO;
        int itemIndex = 1;
        
        for (Map<String, Object> item : items) {
            // 获取项目单价
            BigDecimal price = (BigDecimal) item.get("price");
            if (price == null) {
                price = BigDecimal.ZERO;
            }
            
            // 获取执行周期（1:每日 2:每周 3:每月）
            Integer executionCycle = (Integer) item.get("execution_cycle");
            if (executionCycle == null) {
                executionCycle = 1; // 默认每日
            }
            
            // 获取执行频次（每次执行的次数）
            Integer executionFrequency = (Integer) item.get("execution_frequency");
            if (executionFrequency == null) {
                executionFrequency = 1; // 默认1次
            }
            
            // 计算月周期系数
            int cycleFactor;
            String cycleText;
            switch (executionCycle) {
                case 1: // 每日
                    cycleFactor = 30; // 30天
                    cycleText = "每日";
                    break;
                case 2: // 每周
                    cycleFactor = 4;  // 4周
                    cycleText = "每周";
                    break;
                case 3: // 每月
                    cycleFactor = 1;  // 1次
                    cycleText = "每月";
                    break;
                default:
                    cycleFactor = 1;
                    cycleText = "未知";
            }
            
            // 计算该项目的月费用 = 单价 × 执行频次 × 月周期系数
            BigDecimal itemMonthlyFee = price
                    .multiply(new BigDecimal(executionFrequency))
                    .multiply(new BigDecimal(cycleFactor));
            
            System.out.println("【费用计算】项目" + itemIndex + ": 单价=" + price 
                + " × 频次=" + executionFrequency + " × 周期系数(" + cycleText + ")=" + cycleFactor 
                + " = " + itemMonthlyFee + "元/月");
            
            totalFee = totalFee.add(itemMonthlyFee);
            itemIndex++;
        }
        
        System.out.println("【费用计算】总费用 = " + totalFee + "元/月");
        return totalFee;
    }
    
    /**
     * 更新关联护理等级的费用
     * 
     * @param planId 护理计划ID
     */
    private void updateRelatedNursingLevelFee(Long planId) {
        try {
            // 计算护理计划的月费用
            BigDecimal monthlyFee = calculatePlanMonthlyFee(planId);
            System.out.println("【费用计算】护理计划ID=" + planId + "，计算出的月费用=" + monthlyFee);
            
            // 查询关联的护理等级
            NursingLevel nursingLevel = nursingLevelMapper.selectNursingLevelByPlanId(planId);
            
            if (nursingLevel != null) {
                System.out.println("【费用更新】找到关联的护理等级：" + nursingLevel.getLevelName() 
                    + "，原费用=" + nursingLevel.getNursingFee() + "，新费用=" + monthlyFee);
                // 更新护理等级的护理费用
                nursingLevel.setNursingFee(monthlyFee);
                nursingLevelMapper.updateNursingLevel(nursingLevel);
                System.out.println("【费用更新】护理等级费用更新成功");
            } else {
                System.out.println("【费用更新】警告：护理计划ID=" + planId + " 没有关联任何护理等级");
            }
        } catch (Exception e) {
            System.err.println("【费用更新】更新护理等级费用失败：" + e.getMessage());
            e.printStackTrace();
        }
    }
}
